# -*- coding: utf-8 -*-
# @Time    : 2024/7/15 18:01
# @Author  : yujiahao
# @File    : 31_fastapi_safety.py
# @description:安全性


"""
1. 安全性、身份认证和授权：
    - 处理安全性和身份认证是一个复杂而困难的话题。
    - 在许多框架和系统中，处理安全性和身份认证可能占编写的所有代码的 50％ 或更多。
    - FastAPI 提供了多种工具，帮助你以标准的方式轻松、快速地处理安全性，而无需研究和学习所有的安全规范。

2. OAuth2：
    - OAuth2 是一个规范，定义了几种处理身份认证和授权的方法。
    - 它包括了使用「第三方」进行身份认证的方法，如「使用 Facebook，Google，Twitter，GitHub 登录」。
    - OAuth 1 是 OAuth2 的前身，更为复杂，包含了加密通信的规范，如今已不常用。
    - OAuth2 期望你为应用程序使用 HTTPS 进行通信。

3. OpenID Connect：
    - OpenID Connect 是基于 OAuth2 的规范。
    - 它扩展了 OAuth2，并明确了一些在 OAuth2 中相对模糊的内容，以提高互操作性。
    - 例如，Google 登录使用 OpenID Connect（底层使用 OAuth2），而 Facebook 登录则不支持 OpenID Connect。

4. 其他相关规范：
    - OpenID（非「OpenID Connect」）是另一个试图解决同样问题的规范，但不是基于 OAuth2，如今已不常用。
    - OpenAPI（以前称为 Swagger）是用于构建 API 的开放规范，FastAPI 基于 OpenAPI。
    - OpenAPI 定义了多种安全方案：
        - apiKey：特定于应用程序的密钥，可以来自查询参数、请求头或 cookie。
        - http：标准的 HTTP 身份认证系统，包括 bearer（OAuth2 继承）、HTTP Basic 认证、HTTP Digest 等。
        - oauth2：处理安全性的方式（称为「流程」），包括 implicit、clientCredentials、authorizationCode、password（适用于同一应用程序中处理身份认证）。
        - openIdConnect：定义如何自动发现 OAuth2 身份认证数据的方法（OpenID Connect 规范中定义）。

Tip: 集成其他身份认证/授权提供者（例如 Google，Facebook，Twitter，GitHub 等）也是可能的，而且较为容易。最复杂的问题是创建一个身份认证/授权提供程序，但 FastAPI 提供了轻松完成任务的工具，同时为你解决了重活。
"""

from typing import Annotated

from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer

app = FastAPI()

# todo 密码流（Password Flow）

"""
Password 流是 OAuth2 定义的，用于处理安全与身份验证的方式（流）。

OAuth2 的设计目标是为了让后端或 API 独立于服务器验证用户身份。
但在本例中，FastAPI 应用会处理 API 与身份验证。

简化的运行流程：
1. 用户在前端输入 username 与 password，并点击回车。
2. 前端（用户浏览器中运行的）把 username 与 password 发送至 API 中指定的 URL（使用 tokenUrl="token" 声明）。
3. API 检查 username 与 password，并用令牌（Token）响应（暂未实现此功能）：
    - 令牌只是用于验证用户的字符串。
    - 一般来说，令牌会在一段时间后过期。
    - 过时后，用户要再次登录。
    - 这样一来，就算令牌被人窃取，风险也较低。因为它与永久密钥不同，在绝大多数情况下不会长期有效。
4. 前端临时将令牌存储在某个位置。
5. 用户点击前端，前往前端应用的其它部件。
6. 前端需要从 API 中提取更多数据：
    - 为指定的端点（Endpoint）进行身份验证。
    - 因此，用 API 验证身份时，要发送值为 Bearer + 令牌的请求头 Authorization。
    - 假如令牌为 foobar，Authorization 请求头就是：Bearer foobar。
"""

# todo FastAPI 的 OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

'''
FastAPI 提供了不同抽象级别的安全工具。

本例使用 OAuth2 的 Password 流以及 Bearer 令牌（Token）。为此要使用 OAuth2PasswordBearer 类。

【说明】

    Bearer 令牌不是唯一的选择。但它是最适合这个用例的方案。

    甚至可以说，它是适用于绝大多数用例的最佳方案，除非您是 OAuth2 的专家，知道为什么其它方案更合适。

    本例中，FastAPI 还提供了构建工具。

创建 OAuth2PasswordBearer 的类实例时，要传递 tokenUrl 参数。
该参数包含客户端（用户浏览器中运行的前端） 的 URL，用于发送 username 与 password，并获取令牌。

【提示】


    在此，tokenUrl="token" 指向的是暂未创建的相对 URL token。这个相对 URL 相当于 ./token。

    因为使用的是相对 URL，如果 API 位于 https://example.com/，则指向 https://example.com/token。但如果 API 位于 https://example.com/api/v1/，它指向的就是https://example.com/api/v1/token。

    使用相对 URL 非常重要，可以确保应用在遇到使用代理这样的高级用例时，也能正常运行。
'''

# todo 如何创建实际的路径操作。
'''

1、首先要创建 OAuth2PasswordBearer，实例。
    - 严苛的 Pythonista 可能不喜欢用 tokenUrl 这种命名风格代替 token_url。

    - 这种命名方式是因为要使用与 OpenAPI 规范中相同的名字。以便在深入校验安全方案时，能通过复制粘贴查找更多相关信息。

2、使用 Depends 把 oauth2_scheme 传入依赖项。该依赖项使用字符串（str）接收路径操作函数的参数 token 。

    - FastAPI 使用（在依赖项中声明的）类 OAuth2PasswordBearer 在 OpenAPI 中定义安全方案，
        这是因为它继承自 fastapi.security.oauth2.OAuth2，而该类又是继承自fastapi.security.base.SecurityBase。

    - 所有与 OpenAPI（及 API 文档）集成的安全工具都继承自 SecurityBase， 这就是为什么 FastAPI 能把它们集成至 OpenAPI 的原因。
    
【实现的操作】
    - FastAPI 校验请求中的 Authorization 请求头，核对请求头的值是不是由 Bearer ＋ 令牌组成， 并返回令牌字符串（str）。

    - 如果没有找到 Authorization 请求头，或请求头的值不是 Bearer ＋ 令牌。FastAPI 直接返回 401 错误状态码（UNAUTHORIZED）。

    - 开发者不需要检查错误信息，查看令牌是否存在，只要该函数能够执行，函数中就会包含令牌字符串。

像这种的话是基于依赖注入系统的，但是不实用
'''


@app.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
    return {"token": token}
